package com.qfx.common.shiro;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {
	
    /**
     * <h5>功能:凭证匹配器</h5>
     * 
     * @author zhangpj	@date 2018年10月9日
     * @return 
     */
    @Bean
    public HashedCredentialsMatcher hashMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //采用md5加密,没有默认值.可以有MD5或者SHA-1,如果对密码安全有更高要求可以用SHA-256或者更高
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //散列的次数,比如散列两次,相当于md5(md5(md5("")));
        hashedCredentialsMatcher.setHashIterations(3);
        //默认是true,true时用的是Hex编码;false时用Base64编码
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        
        return hashedCredentialsMatcher;
    }
    
    /**
     * <h5>功能:配置shiro session 的一个管理器</h5>
     * 
     * @author zhangpj	@date 2018年10月9日
     * @return 
     */
    @Bean
    public DefaultWebSessionManager sessionManager(){
    	DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
    	defaultWebSessionManager.setSessionDAO(new MemorySessionDAO());
    	// 隐藏在地址栏中显示的JSESSIONID
    	defaultWebSessionManager.setSessionIdUrlRewritingEnabled(false);
    	// session的失效时长,单位毫秒(这里设置为30分钟,实际项目请自行修改)
    	defaultWebSessionManager.setGlobalSessionTimeout(1800000);
    	// 间隔一定时间清理失效会话,单位毫秒(这里设置为每5分钟清理一次用户直接关闭浏览器造成的孤立会话,实际项目请自行修改)
    	defaultWebSessionManager.setSessionValidationInterval(300000);
    	// 描session线程,负责清理超时会话
    	defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
    	// 修改Cookie名称,放止名称和默认的名称冲突
    	SimpleCookie cookie = new SimpleCookie("APPJSESSIONID");
        defaultWebSessionManager.setSessionIdCookie(cookie);
    	
    	return defaultWebSessionManager;
    }
	
	/**
	 * <h5>功能:自定义realm认证类,继承自AuthorizingRealm,负责用户的认证和权限的处理</h5>
	 * 
	 * @author zhangpj	@date 2018年10月11日
	 * @param hashMatcher
	 * @return 
	 */
	@Bean
	public UserRealm userRealm(HashedCredentialsMatcher hashMatcher){
		UserRealm userRealm = new UserRealm();
		userRealm.setCredentialsMatcher(hashMatcher);
		return userRealm;
	}
	
	/**
     * <h5>功能:安全管理器</h5>
     * 权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类
	 * 
	 * @author zhangpj	@date 2018年10月11日
	 * @param userRealm
	 * @param sessionManager
	 * @return 
	 */
	@Bean
    public DefaultWebSecurityManager securityManager(UserRealm userRealm, DefaultWebSessionManager sessionManager){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        // 自定义realm
        securityManager.setRealm(userRealm);
        // shiro 会话管理
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }
	
    /**
     * <h5>功能:自定义权限过滤器</h5>
     * 
     * @author zhangpj	@date 2018年10月11日
     * @param securityManager
     * @return 
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
    	ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    	// 调用我们配置的安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 配置我们的登录请求地址,非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
        shiroFilterFactoryBean.setLoginUrl("/login/401");
        // 设置无权限时跳转的URL
        shiroFilterFactoryBean.setUnauthorizedUrl("/login/403");
        
        Map<String, Filter> filter = shiroFilterFactoryBean.getFilters();
        filter.put("roles", new CustomRolesAuthorizationFilter());
        
        // 设置拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        shiroFilterFactoryBean.setFilters(filter);
        
        // 对静态资源设置匿名访问,从resoutces/static后面开始写
        filterChainDefinitionMap.put("/css/**", "anon");
        // 可匿名访问的地址
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/index.jsp", "anon");
        filterChainDefinitionMap.put("/login/loginPage", "anon");
        filterChainDefinitionMap.put("/login/register", "authc");
        filterChainDefinitionMap.put("/login/login", "anon");
        filterChainDefinitionMap.put("/login/401", "anon");
        filterChainDefinitionMap.put("/login/403", "anon");
        filterChainDefinitionMap.put("/login/404", "anon");
        filterChainDefinitionMap.put("/login/500", "anon");
        // 请求 logout.do地址,shiro去清除session
        filterChainDefinitionMap.put("/logout", "logout");
        
        //循环url,逐个添加到section中。section就是filterChainDefinitionMap,
        //里面的键就是链接URL,值就是存在什么条件才能访问该链接
//        Map<String, SysMenuRole> menuRoleMap = MenuRoleCache.menuRoleCacheMap;
//        for (String key : menuRoleMap.keySet()) {
//        	filterChainDefinitionMap.put(key, "roles["+menuRoleMap.get(key).getRoleNames()+"]");
//		}
        
        //所有url都必须认证通过才可以访问，必须放在最后
        filterChainDefinitionMap.put("/**", "authc");
        
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    	
    	return shiroFilterFactoryBean;
    }
}
